package com.sjtu.vfact.visualization.view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Paint;
import java.awt.geom.Point2D;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;

import org.apache.commons.collections15.functors.ConstantTransformer;
import org.apache.commons.collections15.functors.MapTransformer;
import org.apache.commons.collections15.map.LazyMap;

import com.sjtu.vfact.textual.model.Cluster;
import com.sjtu.vfact.textual.model.Document;
import com.sjtu.vfact.textual.model.MasterTermset;
import com.sjtu.vfact.textual.model.TermSet;
import com.sjtu.vfact.visualization.base.VfactEdge;
import com.sjtu.vfact.visualization.base.VfactVertex;

import edu.uci.ics.jung.algorithms.layout.AggregateLayout;
import edu.uci.ics.jung.algorithms.layout.CircleLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.SparseMultigraph;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.graph.util.Pair;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;

public class GraphPanelv1{
	
	private Graph<VfactVertex, VfactEdge> graph;
	private VisualizationViewer<VfactVertex, VfactEdge> viewer;
	private AggregateLayout<VfactVertex, VfactEdge> layout;
	private GraphZoomScrollPane gzsp;
	
	private Timer timer;
	private boolean animation;
	
	Map<VfactVertex,Paint> vertexPaints = LazyMap.<VfactVertex,Paint>decorate(new HashMap<VfactVertex,Paint>(),
			new ConstantTransformer(Color.WHITE));
	
	public final Color[] colors = {new Color(216, 134, 134), new Color(135, 137, 211), new Color(134, 206, 189),
				new Color(206, 176, 134), new Color(194, 204, 134), new Color(145, 214, 134),
				new Color(133, 178, 209), new Color(103, 148, 255), new Color(60, 220, 220),
				new Color(30, 250, 100)
	};
	
	public void setupView(List<MasterTermset> list){
		graph = new SparseMultigraph<VfactVertex, VfactEdge>();
		
		for(MasterTermset vertex : list){
			graph.addVertex(vertex.getTermset());
		}
		
		layout = new AggregateLayout<VfactVertex, VfactEdge>(new CircleLayout<VfactVertex, VfactEdge>(graph));
		
		viewer = new VisualizationViewer<VfactVertex, VfactEdge>(layout);
		viewer.setBackground(Color.WHITE);
		viewer.getRenderContext().setVertexFillPaintTransformer(MapTransformer.<VfactVertex,Paint>getInstance(vertexPaints));
		colorVertices(graph.getVertices(), Color.RED);
		
		viewer.setVertexToolTipTransformer(new ToStringLabeller<VfactVertex>());
		
		final DefaultModalGraphMouse<VfactVertex, String> graphMouse = new DefaultModalGraphMouse<VfactVertex, String>();
		viewer.setGraphMouse(graphMouse);
		
		gzsp = new GraphZoomScrollPane(viewer);
	}
	
	public void setupSSAView(Map<TermSet, Set<Document>> ssaDict){
		graph = new DirectedSparseMultigraph<VfactVertex, VfactEdge>();
		
		int edgeId = 1;
		for(Map.Entry<TermSet, Set<Document>> entry : ssaDict.entrySet()){
			TermSet key = entry.getKey();
			Set<Document> value = entry.getValue();
			graph.addVertex(key);
			colorVertex(key, colors[1]);
			for(Document doc : value){
				graph.addVertex(doc);
				colorVertex(doc, colors[2]);
				graph.addEdge(new VfactEdge(edgeId, "Edge-" + edgeId), doc, key, EdgeType.DIRECTED);
			}
		}
		
		layout = new AggregateLayout<VfactVertex, VfactEdge>(new CircleLayout<VfactVertex, VfactEdge>(graph));
		
		viewer = new VisualizationViewer<VfactVertex, VfactEdge>(layout);
		viewer.setBackground(Color.WHITE);
		viewer.getRenderContext().setVertexFillPaintTransformer(MapTransformer.<VfactVertex,Paint>getInstance(vertexPaints));
		
		viewer.setVertexToolTipTransformer(new ToStringLabeller<VfactVertex>());
		
		final DefaultModalGraphMouse<VfactVertex, String> graphMouse = new DefaultModalGraphMouse<VfactVertex, String>();
		viewer.setGraphMouse(graphMouse);
		
		gzsp = new GraphZoomScrollPane(viewer);
	}
	
	public GraphZoomScrollPane getGZSP(){
		return this.gzsp;
	}
	
	public Graph<VfactVertex, VfactEdge> getGraph(){
		return graph;
	}
	
	public void unclusterGraph(){
		layout.removeAll();
		viewer.setGraphLayout(layout);
		colorVertices(graph.getVertices(), Color.RED);
	}
	
	public void clusterGraph(List<Cluster<VfactVertex>> clusters){
		int i = 0;
		for(Cluster<VfactVertex> c : clusters){
			paintCluster(c);
			Color color = colors[i % colors.length];
			colorVertices(c.getAllVertices(), color);
			i++;
		}
	}
	
	private void paintCluster(Cluster<VfactVertex> cluster){
		Collection<VfactVertex> vertices = cluster.getAllVertices();
		Point2D center = new Point2D.Double();
		double x = 0.0;
		double y = 0.0;
		for(VfactVertex vertex : vertices){
			Point2D p = layout.transform(vertex);
			x += p.getX();
			y += p.getY();
		}
		
		x /= cluster.getSize();
		y /= cluster.getSize();
		center.setLocation(x, y);
		
		Graph<VfactVertex, VfactEdge> subgraph;
		try {
			subgraph = graph.getClass().newInstance();
			for(VfactVertex vertex : vertices){
				subgraph.addVertex(vertex);
				Collection<VfactEdge> incidentEdges = graph.getIncidentEdges(vertex);
				for(VfactEdge edge : incidentEdges){
					Pair<VfactVertex> endpoints = graph.getEndpoints(edge);
					if(vertices.containsAll(endpoints)){
						subgraph.addEdge(edge, endpoints.getFirst(), endpoints.getSecond());
					}
				}
			}
			
			Layout<VfactVertex, VfactEdge> subLayout = new CircleLayout<VfactVertex, VfactEdge>(subgraph);
			subLayout.setInitializer(viewer.getGraphLayout());
			subLayout.setSize(new Dimension(75, 75));
			layout.put(subLayout, center);
			viewer.setGraphLayout(layout);
			
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
	
	private void colorVertices(Collection<VfactVertex> vertices, Color color){
		for(VfactVertex vertex : vertices){
			vertexPaints.put(vertex, color);
		}
		
	}
	
	private void colorVertex(VfactVertex vertex, Color color){
		vertexPaints.put(vertex, color);
	}
	
//	private void markPrototype(){
//		vv.getRenderContext().setVertexDrawPaintTransformer(new Transformer<Number,Paint>() {
//			public Paint transform(Number v) {
//				if(vv.getPickedVertexState().isPicked(v)) {
//					return Color.cyan;
//				} else {
//					return Color.BLACK;
//				}
//			}
//		});
//
//	}
	
}
